package projects.Olympic;

import java.io.File;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import org.dbunit.Assertion;
import org.dbunit.DatabaseTestCase;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.junit.Test;
import org.dbunit.operation.*;


public class AthleteRepositoryTest extends DatabaseTestCase{
	private Athlete deRossi;
	private Athlete totti;
	private Athlete federer;
	private Athlete miller;
	protected IDataSet getDataSet() throws Exception {
		this.deRossi=new Athlete();
		this.totti=new Athlete();
		this.federer=new Athlete();
		this.miller=new Athlete();
		this.deRossi.setName("De Rossi");
		this.deRossi.setCode(3);
		this.deRossi.setHeight(186);
		this.deRossi.setNation("Italy");
		Calendar c=Calendar.getInstance();
		c.set(1982, 3, 22);
		this.deRossi.setBirthDate(c.getTime());
		this.totti.setCode(1);
		this.totti.setName("Totti");
		this.totti.setNation("Italy");
		this.totti.setHeight(182);
		c.set(1977, 8, 3);
		this.totti.setBirthDate(c.getTime());
		this.federer.setCode(4);
		this.federer.setName("Federer");
		this.federer.setNation("Swizerland");
		this.federer.setHeight(185);
		c.set(1979, 5, 20);
		this.federer.setBirthDate(c.getTime());
		this.miller.setCode(2);
		this.miller.setName("Miller");
		this.miller.setNation("Austria");
		this.miller.setHeight(178);
		c.set(1975,6,5);
		this.miller.setBirthDate(c.getTime());
		
		return new FlatXmlDataSet(new FileInputStream("two_athletes.xml"));
		
	}
	
	protected IDatabaseConnection getConnection() throws Exception {
		  Class.forName("org.postgresql.Driver");
		  Connection jdbcConnection =
		    DriverManager.getConnection("jdbc:postgresql://localhost:5432/Olympic", "postgres", "asroma");
		  return new DatabaseConnection(jdbcConnection);
	}
	

	
	@Test
	public void testPersist() throws Exception{
		AthleteRepository ar=new AthleteRepository();
		ar.persist(this.deRossi);
		
		IDataSet databaseDataSet = this.getConnection().createDataSet();
        ITable actualTable = databaseDataSet.getTable("athletes");
        
        IDataSet expectedDataSet = new FlatXmlDataSet(new File("three_athletes.xml"));
        ITable expectedTable = expectedDataSet.getTable("athletes");
        
        Assertion.assertEquals(expectedTable, actualTable);
		
		
	}
	
	@Test
	public void testPersistDuplicate(){
		AthleteRepository at=new AthleteRepository();
		try{
			at.persist(this.totti);
			fail("Insert a duplicate should throw an exception!");
		}
		catch(PersistenceException e){
			try{
				IDataSet databaseDataSet = this.getConnection().createDataSet();
		        ITable actualTable = databaseDataSet.getTable("athletes");
		        
		        IDataSet expectedDataSet = new FlatXmlDataSet(new File("two_athletes.xml"));
		        ITable expectedTable = expectedDataSet.getTable("athletes");
		        
		        Assertion.assertEquals(actualTable, expectedTable);
			}
			catch(Exception e1){
				e1.printStackTrace();
			}
		}
	}
	
	@Test
	public void testDelete() throws Exception{
		AthleteRepository at=new AthleteRepository();
		at.delete(this.totti);
		
		IDataSet databaseDataSet=this.getConnection().createDataSet();
		ITable actualTable = databaseDataSet.getTable("athletes");
		
		IDataSet expectedDataSet=new FlatXmlDataSet(new File("one_athlete.xml"));
		ITable expectedTable=expectedDataSet.getTable("athletes");
		
		Assertion.assertEquals(expectedTable, actualTable);
	}
	
	@Test
	public void testDeleteAthleteMissing() throws Exception{
		AthleteRepository at=new AthleteRepository();
		at.delete(this.deRossi);
		
		IDataSet databaseDataSet=this.getConnection().createDataSet();
		ITable actualTable=databaseDataSet.getTable("athletes");
		
		IDataSet expectedDataSet=new FlatXmlDataSet(new File("two_athletes.xml"));
		ITable expectedTable=expectedDataSet.getTable("athletes");
		
		Assertion.assertEquals(expectedTable, actualTable);
	}
	
	@Test
	public void testFindByPrimaryKey() throws Exception{
		AthleteRepository at=new AthleteRepository();
		Athlete a=at.findByPrimaryKey(1);
		assertNotNull(a);
		assertEquals(a.getName(),"Totti");
		assertEquals(1,a.getCode());
		assertEquals(a.getNation(),"Italy");	
	}
	
	@Test
	public void testFindByPrimaryKeyByUknownCode() throws Exception{
		AthleteRepository at=new AthleteRepository();
		Athlete a=at.findByPrimaryKey(3);
		assertNull(a);
	}
	@Test
	public void testUpdateCodeDoesntExist() throws Exception{
		AthleteRepository at=new AthleteRepository();
		at.update(this.deRossi);
		
		IDataSet databaseDataSet=this.getConnection().createDataSet();
		ITable actualTable=databaseDataSet.getTable("athletes");
		
		IDataSet expectedDataSet=new FlatXmlDataSet(new File("three_athletes.xml"));
		ITable expectedTable=expectedDataSet.getTable("athletes");
		
		Assertion.assertEquals(expectedTable, actualTable);
	}
	
	@Test
	public void testUpdate() throws Exception{
		AthleteRepository at=new AthleteRepository();
		this.deRossi.setCode(1);
		at.update(this.deRossi);
		
		IDataSet databaseDataSet=this.getConnection().createDataSet();
		ITable actualTable=databaseDataSet.getTable("athletes");
		
		IDataSet expectedDataSet=new FlatXmlDataSet(new File("two_athletes_modified.xml"));
		ITable expectedTable=expectedDataSet.getTable("athletes");
		
		Assertion.assertEquals(expectedTable, actualTable);
		
	}
	
	@Test 
	public void testFindAll() throws Exception{
		AthleteRepository at=new AthleteRepository();
		IDataSet aggiungiAtleti=new FlatXmlDataSet(new File("Federer,DeRossi.xml"));
		TransactionOperation tr=new TransactionOperation(DatabaseOperation.INSERT);
		tr.execute(this.getConnection(),aggiungiAtleti);
		Map<Integer,Athlete> code2athlete=new HashMap<Integer,Athlete>();
		for(Athlete a:at.findAll()){
			code2athlete.put(a.getCode(),a);
		}
		assertTrue(code2athlete.size()==4);
		assertEquals(this.totti.getName(),code2athlete.get(1).getName());
		assertEquals(this.deRossi,code2athlete.get(3));
		assertEquals(this.federer,code2athlete.get(4));
		assertEquals(this.totti,code2athlete.get(1));
		assertTrue(code2athlete.containsValue(this.deRossi));
		
	}
	
	@Test
	public void testFindAllWithNoElements() throws Exception{
		AthleteRepository at=new AthleteRepository();
		TransactionOperation tr=new TransactionOperation(DatabaseOperation.DELETE);
		tr.execute(this.getConnection(),this.getDataSet());
		assertNull(at.findAll());	
	}
	
	@Test
	public void testFindTallAthletes() throws Exception{
		AthleteRepository at=new AthleteRepository();
		IDataSet aggiungiAtleti=new FlatXmlDataSet(new File("Federer,DeRossi.xml"));
		TransactionOperation tr=new TransactionOperation(DatabaseOperation.INSERT);
		tr.execute(this.getConnection(),aggiungiAtleti);
		Map<Integer,Athlete> code2athlete=new HashMap<Integer,Athlete>();
		for(Athlete a:at.findTallAthletes(182)){
			code2athlete.put(a.getCode(),a);
		}
		assertTrue(code2athlete.size()==2);
		assertTrue(code2athlete.containsValue(this.federer));
		assertTrue(code2athlete.containsValue(this.deRossi));
		assertEquals(code2athlete.get(3),this.deRossi);
		assertEquals(code2athlete.get(4),this.federer);
	}
	
	@Test
	public void testFindTallNoAthletes() throws PersistenceException{
		AthleteRepository at=new AthleteRepository();
		assertNull(at.findTallAthletes(186));
		
	}
	
	@Test
	public void testFindTallEmptyDataBase() throws Exception{
		AthleteRepository at=new AthleteRepository();
		TransactionOperation tr=new TransactionOperation(DatabaseOperation.DELETE);
		tr.execute(this.getConnection(),this.getDataSet());
		assertNull(at.findTallAthletes(0));
	}
	

}
